﻿package com.bizmlib.controls
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.geom.Rectangle;
	import flash.utils.getDefinitionByName;
	
	import fl.core.UIComponent;
	
	
	public class CropTool extends UIComponent
	{
		private static const FILL_COLOR:Number = 0xffffff;
		private static const FILL_ALPHA:Number = .8;
		private static const cursorWidth:Number = 0;
		private static const SPACING:Number = 0;
		
		private var border:MovieClip;
		private var cursorTL:CropToolCursor;
		private var cursorTR:CropToolCursor;
		private var cursorBL:CropToolCursor;
		private var cursorBR:CropToolCursor;
		private var cursorMM:CropToolCursor;
		private var dope:MovieClip;
		
		private var __cropArea:Rectangle;
		private var __kWidthHeight:Number;
		private var __minWidth:Number;
		private var __minHeight:Number;
		
		
		public function CropTool()
		{
		}
		
		
		public function set cropArea(value:Rectangle):void
		{
			__cropArea = value;
			
			correctCropArea(0, 0);
			updateAssetsLocation();
		}
		public function get cropArea():Rectangle
		{
			return __cropArea;
		}
		public function set kWidthHeight(val:Number):void
		{
			__kWidthHeight = val;
			
			correctCropArea(0, 0);
			updateAssetsLocation();
		}
		public function get kWidthHeight():Number
		{
			return __kWidthHeight;
		}
		public function set minWidth(value:Number):void
		{
			//__minWidth = value;
			setMinWidth(value, true, true);
		}
		public function get minWidth():Number
		{
			return __minWidth;
		}
		public function set minHeight(value:Number):void
		{
			//__minHeight = value;
			setMinHeight(value, true, true);
		}
		public function get minHeight():Number
		{
			return __minHeight;
		}
		
		
		override protected function configUI():void
		{
			//trace(this + ".configUI(" + arguments + ")");
			
			super.configUI();
			
			dope = new MovieClip();
			addChild(dope);
			
			var borderSkinClass:Class = getDefinitionByName("CropTool_borderSkin") as Class;
			if(borderSkinClass)
			{
				border = (new borderSkinClass()) as MovieClip;
				addChild(border);
			}
			
			var cursorMiddleSkinClass:Class = getDefinitionByName("CropTool_cursorMiddleSkin") as Class;
			if(cursorMiddleSkinClass)
			{
				cursorMM = (new cursorMiddleSkinClass()) as CropToolCursor;
				addChild(cursorMM);
				cursorMM.middle = true;
				subscribeToCursorEvents(cursorMM);
			}
			
			var cursorCornerSkinClass:Class = getDefinitionByName("CropTool_cursorCornerSkin") as Class;
			if(cursorCornerSkinClass)
			{
				cursorTL = (new cursorCornerSkinClass()) as CropToolCursor;
				addChild(cursorTL);
				subscribeToCursorEvents(cursorTL);
				
				cursorTR = (new cursorCornerSkinClass()) as CropToolCursor;
				addChild(cursorTR);
				cursorTR.rotation = 90;
				cursorTR.left = false;
				subscribeToCursorEvents(cursorTR);
				
				cursorBR = (new cursorCornerSkinClass()) as CropToolCursor;
				addChild(cursorBR);
				cursorBR.rotation = 180;
				cursorBR.top = false;
				cursorBR.left = false;
				subscribeToCursorEvents(cursorBR);
				
				cursorBL = (new cursorCornerSkinClass()) as CropToolCursor;
				addChild(cursorBL);
				cursorBL.rotation = 270;
				cursorBL.top = false;
				subscribeToCursorEvents(cursorBL);
			}
			
			cropArea = cropArea || new Rectangle(0, 0, width, height);
			correctCropArea(0, 0);
			
			updateAssetsLocation()
		}
		override protected function draw():void
		{
			//trace(this + ".draw(" + arguments + ")");
			
			super.draw();
			
			updateAssetsLocation()
		}
		
		
		private function subscribeToCursorEvents(cursor:CropToolCursor):void
		{
			cursor.addEventListener(CropToolCursor.EVENT_DRAG_INVOKED, cursorDragInvoked);
			cursor.addEventListener(CropToolCursor.EVENT_DRAG_STOP_INVOKED, cursorDragStopInvoked);
			cursor.addEventListener(CropToolCursor.EVENT_DRAGGING, cursorDragging);
		}
		private function unsubscribeFromCursorEvents(cursor:CropToolCursor):void
		{
			cursor.removeEventListener(CropToolCursor.EVENT_DRAG_INVOKED, cursorDragInvoked);
			cursor.removeEventListener(CropToolCursor.EVENT_DRAG_STOP_INVOKED, cursorDragStopInvoked);
			cursor.removeEventListener(CropToolCursor.EVENT_DRAGGING, cursorDragging);
		}
		
		private function cursorDragInvoked(event:Event):void
		{
			//trace(this + ".cursorDragInvoked(" + arguments + ")");
			
			var cursor:CropToolCursor = event.target as CropToolCursor;
			if(!cursor)
			{
				return;
			}
			
			var localLeft:Number = 0;
			var localTop:Number = 0;
			var localRight:Number = width;
			var localBottom:Number = height;
			
			if(cursor.middle)
			{
				var cropWidth:Number = Math.floor(cropArea.right - cropArea.left);
				var cropHeight:Number = Math.floor(cropArea.bottom - cropArea.top);
				localLeft = cropWidth/2;
				localRight = width - (cropWidth/2 + ((cropWidth%2>0)?1:0));
				localTop = cropHeight/2;
				localBottom = height - (cropHeight/2 + ((cropHeight%2>0)?1:0));
			}
			else
			{
				if(cursor.isRight){
					localLeft = cropArea.left + 2*cursorWidth + SPACING;
				}else if(cursor.isLeft){
					localRight = cropArea.right - 2*cursorWidth - SPACING;
				}
				if(cursor.isBottom){
					localTop = cropArea.top + 2*cursorWidth + SPACING;
				}else if(cursor.isTop){
					localBottom = cropArea.bottom - 2*cursorWidth - SPACING;
				}
				if(!isNaN(minWidth))
				{
					if(cursor.isRight)
					{
						localLeft = Math.max(localLeft, cropArea.left + minWidth);
					}
					else if(cursor.isLeft)
					{
						localRight = Math.min(localRight, cropArea.right - minWidth);
					}
				}
				if(!isNaN(minHeight))
				{
					if(cursor.isTop)
					{
						localBottom = Math.min(localBottom, cropArea.bottom - minHeight);
					}
					else if(cursor.isBottom)
					{
						localTop = Math.max(localTop, cropArea.top + minHeight);
					}
				}
			}
			
			//trace("localTop=" + localTop + "\tlocalRight=" + localRight + "\tlocalBottom=" + localBottom + "\tlocalLeft=" + localLeft);
			//trace(cursorMC);
			
			cursor.startDrag(false, new Rectangle(localLeft, localTop, localRight - localLeft, localBottom - localTop));
		}
		private function cursorDragStopInvoked(event:Event):void
		{
			//trace(this + ".cursorDragStopInvoked(" + arguments + ")");
			
			var cursor:CropToolCursor = event.target as CropToolCursor;
			if(!cursor)
			{
				return;
			}
			
			cursor.stopDrag();
			updateAssetsLocation();
		}
		private function cursorDragging(event:Event):void
		{
			//trace(this + ".cursorDragging(" + arguments + ")");
			
			var cursor:CropToolCursor = event.target as CropToolCursor;
			if(!cursor)
			{
				return;
			}
			
			var left:Number = cursor.dragBounds.left;
			var top:Number = cursor.dragBounds.top;
			var right:Number = cursor.dragBounds.right;
			var bottom:Number = cursor.dragBounds.bottom;
			//trace("mouseX:" + mouseX + "\tdragBounds:" + cursor.dragBounds + "\tright:" + right);
			
			if(cursor.middle)
			{
				var cropWidth:Number = cropArea.right - cropArea.left;
				var cropHeight:Number = cropArea.bottom - cropArea.top;
				var xmouse:Number = Math.min(right, Math.max(left, mouseX + (((cropWidth%2)>0)?.5:0)));
				var ymouse:Number = Math.min(bottom, Math.max(top, mouseY + (((cropHeight%2)>0)?.5:0)));
				cropArea.left = xmouse - cropWidth/2;
				cropArea.right = cropArea.left + cropWidth;
				cropArea.top = ymouse - cropHeight/2;
				cropArea.bottom = cropArea.top + cropHeight;
			}
			else
			{
				if(cursor.isRight){
					cropArea.right = Math.min(right, Math.max(left, Math.ceil(mouseX)));
				}else if(cursor.isLeft){
					cropArea.left = Math.min(right, Math.max(left, Math.floor(mouseX)));
				}
				//trace("cropArea.left:" + cropArea.left);
		
				if(cursor.isBottom){
					cropArea.bottom = Math.max(top, Math.min(bottom, Math.ceil(mouseY)));
				}else if(cursor.isTop){
					cropArea.top = Math.max(top, Math.min(bottom, Math.floor(mouseY)));
				}
			}
			
			correctCropArea(cursor.isLeft?1:-1, cursor.isTop?1:-1);
			
			updateAssetsLocation();
		}
		
		private function setMinWidth(value:Number, updateMinHeight:Boolean = false, reDrawLayout:Boolean = false):void
		{
			__minWidth = value;
			if(updateMinHeight && kWidthHeight>0)
			{
				setMinHeight(minWidth/kWidthHeight, false, false);
			}
			if(reDrawLayout)
			{
				correctCropArea(0, 0);
				updateAssetsLocation();
			}
		}
		private function setMinHeight(value:Number, updateMinWidth:Boolean = false, reDrawLayout:Boolean = false):void
		{
			__minHeight = value;
			if(updateMinWidth && kWidthHeight>0)
			{
				setMinWidth(minHeight*kWidthHeight, false, false);
			}
			if(reDrawLayout)
			{
				correctCropArea(0, 0);
				updateAssetsLocation();
			}
		}
		
		private function correctCropArea(baseX:Number, baseY:Number):void
		{
			var localWidth:Number = cropArea.right - cropArea.left;
			var localHeight:Number = cropArea.bottom - cropArea.top;
			var localWidthDiv2:Number = localWidth/2;
			var localHeightDiv2:Number = localHeight/2;
			
			if(localWidth/localHeight < kWidthHeight)
			{
				localHeight = Math.round(localWidth/kWidthHeight);
			}else if(localWidth/localHeight > kWidthHeight)
			{
				localWidth = Math.round(localHeight*kWidthHeight);
			}
			
			switch(baseX){
				case -1:
					cropArea.right = cropArea.left + localWidth;
					break;
				case 0:
					cropArea.left = Math.round(cropArea.left + localWidthDiv2 - localWidth/2);
					cropArea.right = cropArea.left + localWidth;
					break;
				case 1:
					cropArea.left = cropArea.right - localWidth;
					break;
			}
			
			switch(baseY){
				case -1:
					cropArea.bottom = cropArea.top + localHeight;
					break;
				case 0:
					cropArea.top = Math.round(cropArea.top + localHeightDiv2 - localHeight/2);
					cropArea.bottom = cropArea.top + localHeight;
					break;
				case 1:
					cropArea.top = cropArea.bottom - localHeight;
					break;
			}
			/**
			cursorMM.width = localWidth;
			cursorMM.height = localHeight;
			/**/
		}
		
		private function updateAssetsLocation():void
		{
			cursorTL.x = cropArea.left;
			cursorBL.x = cropArea.left;
			cursorTR.x = cropArea.right;
			cursorBR.x = cropArea.right;
			cursorTL.y = cropArea.top;
			cursorTR.y = cropArea.top;
			cursorBL.y = cropArea.bottom;
			cursorBR.y = cropArea.bottom;
			/**
			cursorMM.x = Math.round(cropArea.left + (cropArea.right - cropArea.left)/2 - cursorMM.width/2);
			cursorMM.y = Math.round(cropArea.top + (cropArea.bottom - cropArea.top)/2 - cursorMM.height/2);
			/**/
			cursorMM.x = cropArea.left + (cropArea.right - cropArea.left)/2 - cursorMM.width/2;
			cursorMM.y = cropArea.top + (cropArea.bottom - cropArea.top)/2 - cursorMM.height/2;
	
			border.x = cropArea.left;
			border.y = cropArea.top;
			border.width = cropArea.right - cropArea.left;
			border.height = cropArea.bottom - cropArea.top;
	
			dope.graphics.clear();
			dope.graphics.beginFill(FILL_COLOR, FILL_ALPHA);
			dope.graphics.moveTo(0, 0);
			dope.graphics.lineTo(cropArea.left, 0);
			dope.graphics.lineTo(cropArea.left, height);
			dope.graphics.lineTo(0, height);
			dope.graphics.lineTo(0, 0);
			dope.graphics.endFill();
			dope.graphics.beginFill(FILL_COLOR, FILL_ALPHA);
			dope.graphics.moveTo(cropArea.left, 0);
			dope.graphics.lineTo(cropArea.right, 0);
			dope.graphics.lineTo(cropArea.right, cropArea.top);
			dope.graphics.lineTo(cropArea.left, cropArea.top);
			dope.graphics.lineTo(cropArea.left, 0);
			dope.graphics.endFill();
			dope.graphics.beginFill(FILL_COLOR, FILL_ALPHA);
			dope.graphics.moveTo(cropArea.left, cropArea.bottom);
			dope.graphics.lineTo(cropArea.right, cropArea.bottom);
			dope.graphics.lineTo(cropArea.right, height);
			dope.graphics.lineTo(cropArea.left, height);
			dope.graphics.lineTo(cropArea.left, cropArea.bottom);
			dope.graphics.endFill();
			dope.graphics.beginFill(FILL_COLOR, FILL_ALPHA);
			dope.graphics.moveTo(cropArea.right, 0);
			dope.graphics.lineTo(width, 0);
			dope.graphics.lineTo(width, height);
			dope.graphics.lineTo(cropArea.right, height);
			dope.graphics.lineTo(cropArea.right, 0);
			dope.graphics.endFill();
		}
	}
}